package com.hspedu.bot.consume;

import com.alibaba.fastjson.JSONObject;
import com.hspedu.bot.consume.utils.Game;
import com.hspedu.bot.consume.utils.JwtAuthentication;
import com.hspedu.bot.pojo.Bot;
import com.hspedu.bot.pojo.User;
import com.hspedu.bot.service.user.bot.BotService;
import com.hspedu.bot.service.record.RecordService;
import com.hspedu.bot.service.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/{token}")  // 注意不要以'/'结尾
public class WebSocketServer {

    //与线程安全有关的哈希表，将userID映射到相应用户的WebSocketServer
    final public static ConcurrentHashMap<Integer, WebSocketServer> users = new ConcurrentHashMap<>();

    //当前链接请求的用户
    private User user;

    //后端向前端发信息,每个链接用session维护
    private Session session = null;

    public static UserService userService;
    public static RecordService recordService;
    private static BotService botService;

    //游戏地图
    public Game game = null;

    //跨服务访问
    public static RestTemplate restTemplate;
    private final static String addPlayerUrl = "http://127.0.0.1:3001/player/add/";
    private final static String removePlayerUrl = "http://127.0.0.1:3001/player/remove/";

    @Autowired
    public void setUserService(UserService userService) {
        WebSocketServer.userService = userService;
    }

    @Autowired
    public void setRecordService(RecordService recordService) {
        WebSocketServer.recordService = recordService;
    }

    @Autowired
    public void setBotService(BotService botService) {
        WebSocketServer.botService = botService;
    }


    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        WebSocketServer.restTemplate = restTemplate;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        // 建立连接
        this.session = session;
        System.out.println("connection");
        int userId = JwtAuthentication.getUserId(token);
        this.user = userService.getById(userId);

        if (this.user != null) {
            users.put(userId, this);
        } else {
            this.session.close();
        }
    }

    @OnClose
    public void onClose() {
        // 关闭链接
        System.out.println("disconnection");
        //断开连接的话要将user移除
        if (this.user != null) {
            users.remove(this.user.getId());
        }
    }

    //为服务返回url调用该方法开始游戏
    public static void startGame(Integer aid, Integer aBotId, Integer bid, Integer bBotId) {
        User a = userService.getById(aid), b = userService.getById(bid);
        Bot botA = botService.getById(aBotId), botB = botService.getById(bBotId);

        //生成地图
        Game game = new Game(13,
                14,
                20,
                a.getId(),
                botA,
                b.getId(),
                botB
        );
        game.createMap();
        if (users.get(a.getId()) != null)
            users.get(a.getId()).game = game;
        if (users.get(b.getId()) != null)
            users.get(b.getId()).game = game;

        game.start();               //启动线程

        //游戏相关的信息封装成一个JSONObject
        JSONObject respGame = new JSONObject();
        respGame.put("a_id", game.getPlayerA().getId());
        respGame.put("a_sx", game.getPlayerA().getSx());
        respGame.put("a_sy", game.getPlayerA().getSy());

        respGame.put("b_id", game.getPlayerB().getId());
        respGame.put("b_sx", game.getPlayerB().getSx());
        respGame.put("b_sy", game.getPlayerB().getSy());
        respGame.put("map", game.getG());


        //分别给两个用户存储对手的信息
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("event", "start matching");
        jsonObject1.put("username", b.getUsername());
        jsonObject1.put("photo", b.getPhoto());
        jsonObject1.put("game", respGame);
        //用users获取a的链接
        if (users.get(a.getId()) != null)
            users.get(a.getId()).sendMessage(jsonObject1.toJSONString());


        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("event", "start matching");
        jsonObject2.put("username", a.getUsername());
        jsonObject2.put("photo", a.getPhoto());
        jsonObject2.put("game", respGame);
        //用users获取b的链接
        if (users.get(b.getId()) != null)
            users.get(b.getId()).sendMessage(jsonObject2.toJSONString());
    }

    //处理匹配事件
    public void startMatching(String botId) {
        System.out.println("start matching!");
        //向后端发送请求
        MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
        data.add("user_id", this.user.getId().toString());
        data.add("rating", this.user.getRating().toString());
        data.add("bot_id", botId);
        restTemplate.postForObject(addPlayerUrl, data, String.class);
    }

    //处理取消匹配事件
    public void stopMatching() {
        System.out.println("stop matching!");
        //向后端发送请求
        MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
        data.add("user_id", this.user.getId().toString());
        restTemplate.postForObject(removePlayerUrl, data, String.class);
    }

    //处理移动事件[判断是用户A,还是用户B发送过来的移动请求]
    public void moveMatching(Integer direction) {
        if (game.getPlayerA().getId().equals(user.getId())) {           //蛇A
            if (game.getPlayerA().getBotId() == -1) // 人玩
                game.setNextStepA(direction);
        } else if (game.getPlayerB().getId().equals(user.getId())) {
            if (game.getPlayerB().getBotId() == -1) //人玩
                game.setNextStetB(direction);
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // 从Client接收消息
        System.out.println("receive message");
        JSONObject jsonObject = JSONObject.parseObject(message);
        String event = jsonObject.getString("event");
        if ("start matching".equals(event)) {       //根据前端匹配按钮处理不同情况[start matching、stop matching]！！
            this.startMatching(jsonObject.getString("bot_id"));
        } else if ("stop matching".equals(event)) {
            this.stopMatching();
        } else if ("move".equals(event)) {          //用户wasd移动后会发送webSocket请求
            Integer direction = jsonObject.getInteger("direction");
            this.moveMatching(direction);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    //后端向前端发送信息
    public void sendMessage(String message) {
        synchronized (this.session) {
            try {
                this.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}